Skip to content

feat(sessions): modernize conversation thread with collapsible tool groups#2673

Merged
adamleithp merged 2 commits into
mainfrom
feat/thread-collapsed-by-default
Jun 16, 2026
Merged

feat(sessions): modernize conversation thread with collapsible tool groups#2673
adamleithp merged 2 commits into
mainfrom
feat/thread-collapsed-by-default

Conversation

@adamleithp

@adamleithp adamleithp commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What

Rebuilds the conversation thread around a single, consistent tool-call row.

Very much tested locally, all settings types, works really well.

  • One ToolRow primitive (base-ui Collapsible): trigger = icon + text, content = left-padded box. Every tool view — execute, read, edit, search, fetch, think, MCP, generic, thinking — renders through it, replacing the old per-view card markup.
  • Collapsible tool groups. A turn's tool work folds into a group chip with a verb-led summary (Ran 25 commands, read a file, edited a file) that shows the live action while running. Persisted collapse mode in Settings: All collapsed (default) / Collapse when finished turn / No collapsing. Per-chip expand/collapse overrides held in session view state.
  • Always-visible rows. Setup/clone progress (progress_group) and MCP-app tool calls stay outside groups so MCP iframes keep their mount (keepMounted).
  • Assistant text inside a group is indented to the tool-title column.
image image image image

Perf

  • Grouping is a single pass per streamed token producing rows + keepMounted + id→row map (was several walks), with cached summaries for frozen turns.
  • No per-scroll re-renders.

Notes

  • Known pre-existing, unrelated: cloud threads can show a duplicate user message (a mergeConversationItems dedup gap when an attachment is inlined as text vs. a chip). Not touched here.

🤖 Generated with Claude Code

…roups

Unify every tool call (including MCP) onto one ToolRow primitive built on
base-ui Collapsible: a trigger (icon + text) plus a left-padded content box,
replacing the per-tool-view card markup.

A turn's tool-call work folds into a collapsible group chip with a verb-led
summary ("Ran 25 commands, read a file, edited a file") that shows the live
action while the turn runs. Collapse mode is persisted in settings
(all / collapse-when-finished / none, default all); per-chip overrides live in
session view state. Setup/clone progress and MCP-app tool calls stay always
visible so MCP iframes keep their mount.

Grouping is a single pass per token producing rows + keepMounted + id→row map,
with cached summaries for frozen turns and no per-scroll re-renders. Assistant
text inside a group is indented to the tool-title column. No feature flag.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@adamleithp adamleithp added the Stamphog This will request an autostamp by stamphog on small changes label Jun 15, 2026
@adamleithp adamleithp enabled auto-merge (squash) June 15, 2026 10:58
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

React Doctor found 7 issues in 3 files · 7 warnings.

7 warnings

src/features/sessions/components/ConversationView.tsx

src/features/sessions/components/new-thread/ToolCallGroupChip.tsx

src/features/sessions/components/session-update/ToolRow.tsx

Reviewed by React Doctor for commit 35ead45.

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR exceeds the automated review size ceiling (1730 lines, 26 files) and has zero reviews. A feature of this scope — refactoring the conversation thread with new grouping logic and new components — needs at least one human reviewer before auto-approval.

@stamphog stamphog Bot removed the Stamphog This will request an autostamp by stamphog on small changes label Jun 15, 2026
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
packages/ui/src/features/sessions/components/session-update/ReadToolView.tsx:33-42
The image body carries its own `p-2` padding, but `ToolRow`'s content wrapper already adds `p-2` around every `content` node, so the image ends up with effectively `p-4` total padding instead of the previous `p-2`. The gray background (`bg-(--gray-2)`) is also applied only to the inner div rather than to the border box itself, leaving a white gap between the border and the gray area that didn't exist before.

```suggestion
  const body = imageContent ? (
    <SafeImagePreview
      base64={imageContent.base64}
      mimeType={imageContent.mimeType}
      alt={filePath || "Read tool image preview"}
      className="max-h-96 max-w-full object-contain"
    />
  ) : fileContent ? (
```

### Issue 2 of 2
packages/ui/src/features/sessions/components/new-thread/conversationThreadConfig.ts:67-77
**`messages` count is tracked but never surfaced**

`GroupCounts.messages` is incremented for `agent_message_chunk` and `console` session updates in `summarize()`, but `buildDoneLabel` references every other field (`execute`, `read`, `edit`, `delete`, `move`, `search`, `fetch`, `subagents`, `other`) and ignores `messages` entirely. The field is either dead (if mid-turn agent messages can't appear in `leading` after the trailing peel) or silently drops data that a future segment would need. Either remove the field from the interface or add a corresponding segment to `buildDoneLabel`.

Reviews (1): Last reviewed commit: "style(sessions): soften inline-code chip..." | Re-trigger Greptile

Comment on lines +33 to +42
const body = imageContent ? (
<div className="bg-(--gray-2) p-2">
<SafeImagePreview
base64={imageContent.base64}
mimeType={imageContent.mimeType}
alt={filePath || "Read tool image preview"}
className="max-h-96 max-w-full object-contain"
/>
</div>
) : fileContent ? (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The image body carries its own p-2 padding, but ToolRow's content wrapper already adds p-2 around every content node, so the image ends up with effectively p-4 total padding instead of the previous p-2. The gray background (bg-(--gray-2)) is also applied only to the inner div rather than to the border box itself, leaving a white gap between the border and the gray area that didn't exist before.

Suggested change
const body = imageContent ? (
<div className="bg-(--gray-2) p-2">
<SafeImagePreview
base64={imageContent.base64}
mimeType={imageContent.mimeType}
alt={filePath || "Read tool image preview"}
className="max-h-96 max-w-full object-contain"
/>
</div>
) : fileContent ? (
const body = imageContent ? (
<SafeImagePreview
base64={imageContent.base64}
mimeType={imageContent.mimeType}
alt={filePath || "Read tool image preview"}
className="max-h-96 max-w-full object-contain"
/>
) : fileContent ? (
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/features/sessions/components/session-update/ReadToolView.tsx
Line: 33-42

Comment:
The image body carries its own `p-2` padding, but `ToolRow`'s content wrapper already adds `p-2` around every `content` node, so the image ends up with effectively `p-4` total padding instead of the previous `p-2`. The gray background (`bg-(--gray-2)`) is also applied only to the inner div rather than to the border box itself, leaving a white gap between the border and the gray area that didn't exist before.

```suggestion
  const body = imageContent ? (
    <SafeImagePreview
      base64={imageContent.base64}
      mimeType={imageContent.mimeType}
      alt={filePath || "Read tool image preview"}
      className="max-h-96 max-w-full object-contain"
    />
  ) : fileContent ? (
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +67 to +77
/**
* session_update kinds that never fold into a group — always rendered as
* their own row regardless of collapse mode (e.g. the cloud setup / clone
* progress card).
*/
alwaysVisibleUpdates: new Set<string>(["progress_group"]),
/** Max distinct tool icons shown in a collapsed chip's icon strip. */
maxIconsInChip: 10,
} as const;

/** Per-action tallies for a collapsed group. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 messages count is tracked but never surfaced

GroupCounts.messages is incremented for agent_message_chunk and console session updates in summarize(), but buildDoneLabel references every other field (execute, read, edit, delete, move, search, fetch, subagents, other) and ignores messages entirely. The field is either dead (if mid-turn agent messages can't appear in leading after the trailing peel) or silently drops data that a future segment would need. Either remove the field from the interface or add a corresponding segment to buildDoneLabel.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/features/sessions/components/new-thread/conversationThreadConfig.ts
Line: 67-77

Comment:
**`messages` count is tracked but never surfaced**

`GroupCounts.messages` is incremented for `agent_message_chunk` and `console` session updates in `summarize()`, but `buildDoneLabel` references every other field (`execute`, `read`, `edit`, `delete`, `move`, `search`, `fetch`, `subagents`, `other`) and ignores `messages` entirely. The field is either dead (if mid-turn agent messages can't appear in `leading` after the trailing peel) or silently drops data that a future segment would need. Either remove the field from the interface or add a corresponding segment to `buildDoneLabel`.

How can I resolve this? If you propose a fix, please make it concise.

@adamleithp adamleithp requested a review from a team June 15, 2026 18:33

@charlesvien charlesvien left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@adamleithp adamleithp merged commit 2d05add into main Jun 16, 2026
23 checks passed
@adamleithp adamleithp deleted the feat/thread-collapsed-by-default branch June 16, 2026 06:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants